#include "../Buffer/Buffer.hpp"
namespace BaseContainers { namespace Vector {

template <class TYPE>
class Vector : public BaseContainers::Buffer<TYPE> {
private:
	virtual void setDataPool(){}
	void setDataPool(int const & newSize) {
		Size = newSize;
		data = new TYPE[Size];
	}
	void resizeDataPool(int const & newSize) {
		TYPE * temp = new TYPE[newSize];
		for(int i = 0;i < Size;i++) {
			temp[i] = data[i];
		}
		delete [] data;
		data = temp;
		Size = newSize;
	}

	void shiftLeft(int const & offset) {
		shiftLeftex(0,Size-1,offset);
	}
	boolean shiftLeft_s(int const & offset) {
		return shiftLeftex_s(0,Size-1,offset);
	}
	void shiftLeftex(int const & start,int const & end,int const & offset) {
		for(int i = start;i <= end;i++) {
			data[i] = data[i+offset];
		}
	}
	boolean shiftLeftex_s(int const & start,int const & end,int const & offset) {
		if(start < Size && start >= 0 && end <= Size-1 && end > 0 && end >= start) {
			for(int i = start;i <= end;i++) {
				data[i] = data[i+offset];
			}
		}
	}

	void shiftRight(int const & offset) {
		shiftRightex(0,Size-1,offset);
	}
	boolean shiftRight_s(int const & offset) {
		return shiftRightex_s(0,Size-1,offset);
	}
	void shiftRightex(int const & start,int const & end,int const & offset) {
		for(int i = end;i >= start;i--) {
			if(i+offset > Size)
				resizeDataPool(Size+1);
			data[i+offset] = data[i];
		}
	}
	boolean shiftRightex_s(int const & start,int const & end,int const & offset) {
		if(start < Size && start >= 0 && end <= Size-1 && end > 0 && end >= start) {
			for(int i = end;i >= start;i--) {
				data[i+offset] = data[i];
			}
		}
	}

	void reverse();
	boolean reverse_s();
			
public:
	Vector() {
		setDataPool(20);
	}

	const int getSize() const {
		return Size;
	}

	//Returns a reference to the item at index
	// does not remove the the item
	// but does allow modification of the item
	TYPE * get(int const & index) {
		if(index >= Size)
			return NULL;
		return &data[index];
	}

	//Returns a reference to the object so the value can
	// be evaluated but the item cannot be modified or removed.
	TYPE * const at(int const & index) {
		if(index >= Size)
			return NULL;
		return static_cast<TYPE * const>(&data[index]);
	}

	//Returns whether the list is holding any data whatsoever
	boolean empty() {
		if(Size == 0 || data == NULL || MaxSize == 0)
			return true;
	}

	//Removes and cleans up all data inside the list
	void clear() {
		delete [] data;
		Size = 0;
		MaxSize = 0;
		data = NULL;
	}

	//Removes and cleans up all data inside the list
	// and resets all the lists memory allocations
	void clear_s() {
		delete [] data;
		Size = 0;
		MaxSize = 0;
		data = NULL;
	}

	//Removes and cleans up all data inside the list
	// and resets all the lists memory allocations
	// and returns all items currently in the list before cleaning them up.
	TYPE * const clear_s_r() {
		TYPE * const temp = new TYPE[Size];
		for(int i = 0;i < Size;i++) {
			temp[i] = data[i];
		}
		delete [] data;
		Size = 0;
		MaxSize = 0;
		data = NULL;
		return temp;
	}


	//Puts objects at the beginning of the list
	void add(TYPE const & obj) {
		shiftRightex(0,Size-1,1);
		data[0] = obj;
	}
	boolean add_s(TYPE const & obj);

	void add_array(TYPE * objs);
	boolean add_array_s(TYPE const * const objs);
	TYPE * const add_array_s_r(TYPE const * const objs);

	//Puts objects at the end of the list
	void push(TYPE const & obj);
	boolean push_s(TYPE const & obj);

	void push_array(TYPE * objs);
	boolean push_array_s(TYPE const * const objs);
	TYPE * const push_array_s_r(TYPE const * const objs);

	//Puts objects at the specified location in the list
	void insert(int const & index,TYPE const & obj);
	boolean insert_s(int const & index,TYPE const & obj);

	void insert_array(int const & index,TYPE * objs,int const & size);
	boolean insert_array_s(int const & index,TYPE const * const objs,int const & size);
	TYPE * const insert_array_s_r(int const & index,TYPE const * const objs,int const & size);

	//Grabs the item at the front of the list and returns it, removing it from the list
	TYPE & pull();
	TYPE & pull_s();

	TYPE * pull_array(int const & amount);
	TYPE * const pull_array_c(int const & amount);
	TYPE * pull_array_s(int const & amount);
	TYPE * const pull_array_s_c(int const & amount);

	//Grabs the item at the end of the list and returns it
	TYPE & pop();
	TYPE & pop_s();

	TYPE * pop_array(int const & amount);
	TYPE * const pop_array_c(int const & amount);
	TYPE * pop_array_s(int const & amount);
	TYPE * const pop_array_s_c(int const & amount);
};
typedef _VECTOR_ * PVector;
}}